package com.zhugy.comparecode.config;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.zhugy.comparecode.util.CommonUtils;

public class CompareConfig {
	
	private interface ConfigStringHandler {
		String handle(String orignal);
	}
	
	public static final int TYPE_SINGLE_FILE = 1;
	
	public static final int TYPE_DIRECTORY = 2;
	
	private static final String SEPERATOR = "\\|";
	
	private int type;

	private String path1;
	
	private String path2;
	
	private String ignoreLines1;
	
	private Map<String, Set<Integer>> ignoreLineSet1Map;
	
	private String ignoreLines2;
	
	private Map<String, Set<Integer>> ignoreLineSet2Map;
	
	private String excludeFiles1;
	
	private Set<String> excludeFileSet1;
	
	private String excludeFiles2;
	
	private Set<String> excludeFileSet2;
	
	private String file1ToFile2Map;
	
	private Map<String, String> fileNameMap;
	
	private String excludeExtNames;
	
	private Set<String> excludeExtNameSet;
	
	public int getType() {
		return type;
	}

	public void setType(int type) {
		this.type = type;
	}

	public String getFile1ToFile2Map() {
		return file1ToFile2Map;
	}

	public void setFile1ToFile2Map(String file1ToFile2Map) {
		this.file1ToFile2Map = file1ToFile2Map;
		this.fileNameMap = parseFileMaps(file1ToFile2Map);
	}

	public String getPath1() {
		return path1;
	}

	public void setPath1(String path1) {
		this.path1 = path1;
	}

	public String getPath2() {
		return path2;
	}

	public void setPath2(String path2) {
		this.path2 = path2;
	}

	public String getIgnoreLines1() {
		return ignoreLines1;
	}

	public void setIgnoreLines1(String ignoreLines1) {
		this.ignoreLines1 = ignoreLines1;
		this.ignoreLineSet1Map = parseIgnoreLinesMap(ignoreLines1);
	}

	public String getIgnoreLines2() {
		return ignoreLines2;
	}

	public void setIgnoreLines2(String ignoreLines2) {
		this.ignoreLines2 = ignoreLines2;
		this.ignoreLineSet2Map = parseIgnoreLinesMap(ignoreLines2);
	}

	public String getExcludeFiles1() {
		return excludeFiles1;
	}

	public void setExcludeFiles1(String excludeFiles1) {
		this.excludeFiles1 = excludeFiles1;
		this.excludeFileSet1 = parseExcludeFiles(excludeFiles1);
	}

	public String getExcludeFiles2() {
		return excludeFiles2;
	}

	public void setExcludeFiles2(String excludeFiles2) {
		this.excludeFiles2 = excludeFiles2;
		this.excludeFileSet2 = parseExcludeFiles(excludeFiles2);
	}

	public String getExcludeExtNames() {
		return excludeExtNames;
	}

	public void setExcludeExtNames(String excludeExtNames) {
		this.excludeExtNames = excludeExtNames;
		this.excludeExtNameSet = parseExcludeExtNames(excludeExtNames);
	}
	
	private static Map<String, String> parseFileMaps(String fileMapStr) {
		Map<String, String> result = new HashMap<>();
		if (fileMapStr == null || fileMapStr.length() == 0) {
			return result;
		}
		String[] fileMapItems = fileMapStr.split(SEPERATOR);
		for (String fileMapItem : fileMapItems) {
			if (fileMapItem == null || fileMapItem.length() == 0) {
				throw new RuntimeException("文件映射配置不正确，存在空的配置：" + fileMapStr);
			}
			if (fileMapItem.indexOf(":") <= 0) {
				throw new RuntimeException("文件映射配置不正确，格式不正确：" + fileMapStr + "  不正确的项：" + fileMapItem);
			}
			String[] ss = fileMapItem.split(":");
			if (ss.length != 2) {
				throw new RuntimeException("文件映射配置不正确，用冒号分隔后项目太多：" + fileMapStr + "  不正确的项：" + fileMapItem);
			}
			result.put(ss[0], ss[1]);
		}
		return result;
	}
	
	private static Map<String, Set<Integer>> parseIgnoreLinesMap(String ignoreLinesMapStr) {
		Map<String, Set<Integer>> result = new HashMap<>();
		if (ignoreLinesMapStr == null || ignoreLinesMapStr.length() == 0) {
			return result;
		}
		String[] ignoreLinesItems = ignoreLinesMapStr.split(SEPERATOR);
		for (String ignoreLinesItem : ignoreLinesItems) {
			if (ignoreLinesItem == null || ignoreLinesItem.length() == 0) {
				throw new RuntimeException("忽略行映射配置不正确，存在空的配置：" + ignoreLinesMapStr);
			}
			if (ignoreLinesItem.indexOf(":") < 0) {
				throw new RuntimeException("忽略行映射配置不正确，格式不正确：" + ignoreLinesMapStr + "  不正确的项：" + ignoreLinesItem);
			}
			String[] ss = ignoreLinesItem.split(":");
			try {
				result.put(ss[0], parseIgnoreLines(ss[1]));
			} catch (NumberFormatException e) {
				throw new RuntimeException("忽略行映射配置不正确，格式不正确：" + ignoreLinesMapStr + "  不正确的项：" + ignoreLinesItem, e);
			}
		}
		return result;
	}
	
	private static Set<Integer> parseIgnoreLines(String line) {
		Set<Integer> ignoreLineSet = new HashSet<>();
		if (line == null || line.length() == 0) {
			return ignoreLineSet;
		}
		String[] ignoreLineStrs = line.split(",");
		for (int i = 0; i < ignoreLineStrs.length; i++) {
			String ignoreLine = CommonUtils.trim(ignoreLineStrs[i]);
			if (ignoreLine != null && ignoreLine.length() > 0) {
				ignoreLineSet.add(Integer.parseInt(ignoreLineStrs[i]));
			}
		}
		return ignoreLineSet;
	}
	
	private static Set<String> parseExcludeFiles(String ignoreFileStr) {
		return parseStrToSet(ignoreFileStr, (str) -> CommonUtils.replace(str, "\\", "/"));
	}
	
	private static Set<String> parseExcludeExtNames(String excludeExtNames) {
		return parseStrToSet(excludeExtNames, (str) -> str.toLowerCase());
	}
	
	private static Set<String> parseStrToSet(String str, ConfigStringHandler handler) {
		Set<String> set = new HashSet<>();
		if (str == null || str.length() == 0) {
			return set;
		}
		String[] itemAry = str.split(SEPERATOR);
		for (String item : itemAry) {
			String itemTrim = CommonUtils.trim(item);
			if (CommonUtils.isEmpty(itemTrim)) {
				continue;
			}
			set.add(handler.handle(itemTrim));
		}
		return set;
	}
	
	public boolean isIgnoreLine1(String relativePath, int index) {
		if (ignoreLineSet1Map == null || ignoreLineSet1Map.isEmpty()) {
			return false;
		}
		Set<Integer> ignoreLineSet = ignoreLineSet1Map.get(relativePath);
		if (ignoreLineSet == null || ignoreLineSet.isEmpty()) {
			return false;
		}
		return ignoreLineSet.contains(index);
	}
	
	public boolean isIgnoreLine2(String relativePath, int index) {
		if (ignoreLineSet2Map == null || ignoreLineSet2Map.isEmpty()) {
			return false;
		}
		Set<Integer> ignoreLineSet = ignoreLineSet2Map.get(relativePath);
		if (ignoreLineSet == null || ignoreLineSet.isEmpty()) {
			return false;
		}
		return ignoreLineSet.contains(index);
	}
	
	public boolean isExcludeFile1(String relativePath) {
		if (excludeFileSet1 == null || excludeFileSet1.isEmpty()) {
			return false;
		}
		return excludeFileSet1.contains(relativePath);
	}
	
	public boolean isExcludeFile2(String relativePath) {
		if (excludeFileSet2 == null || excludeFileSet2.isEmpty()) {
			return false;
		}
		return excludeFileSet2.contains(relativePath);
	}
	
	public boolean hasSpecialAssign(String relativePath) {
		if (fileNameMap == null || fileNameMap.isEmpty()) {
			return false;
		}
		return fileNameMap.containsKey(relativePath);
	}
	
	public String getAssignComparePath(String relativePath) {
		if (fileNameMap == null || fileNameMap.isEmpty()) {
			return "";
		}
		return fileNameMap.get(relativePath);
	}
	
	public boolean isExcludeExtName(String path) {
		if (excludeExtNameSet == null || excludeExtNameSet.isEmpty()) {
			return false;
		}
		if (path == null || path.isEmpty()) {
			return false;
		}
		String extName;
		int lastIndexOfDot = path.lastIndexOf(".");
		if (lastIndexOfDot < 0) {
			extName = path;
		} else {
			extName = path.substring(lastIndexOfDot + 1);
		}
		extName = extName.toLowerCase();
		return excludeExtNameSet.contains(extName);
	}
	
	public static void main(String[] args) {
		// {'excludeExtNames':'img|gz|zip','excludeFiles1':'bochsrc|kernel/kernel.asm|kernel/kernel1.asm|kernel/kernel2.asm|kernel/kernel3.asm|kernel/kernel4.asm|kernel/kernel5.asm','file1ToFile2Map':'boot/include/fat12hdr.inc:boot/include/fat12hdr.asm|boot/include/load.inc:boot/include/load_inc.asm|kernel/kernel1.asm:kernel/kernel.asm','ignoreLines1':'boot/boot.asm:24,31|boot/loader.asm:14,15,64|kernel/protect.c:143','path1':'D:\\documents\\source\\osfs\\osfs06-master\\c','path2':'D:\\documents\\source\\osfs\\osfs06-master\\c-z','type':2}
		
		CompareConfig config = new CompareConfig();
		config.setType(TYPE_DIRECTORY);
		config.setPath1("D:\\documents\\source\\osfs\\osfs06-master\\c\\");
		config.setPath2("D:\\documents\\source\\osfs\\osfs06-master\\c-z\\");
		config.setFile1ToFile2Map("boot/include/fat12hdr.inc:boot/include/fat12hdr.asm|boot/include/load.inc:boot/include/load_inc.asm|kernel/kernel1.asm:kernel/kernel.asm");
		config.setIgnoreLines1("boot/boot.asm:24,31|boot/loader.asm:14,15,64");
		config.setExcludeExtNames("c|h|gz|zip");
		config.setExcludeFiles1("bochsrc|Makefile.1");
		System.out.println(JSON.toJSONString(config, SerializerFeature.UseSingleQuotes));
	}
}
